#include "ui.h"

int v1(0);
int v2(0);

//PUBLIC FUNCTIONS
Ui::Ui(Pcqc *pcqc)
{
    motor = pcqc;
    files = new QStringList;
    launchDirectory = QDir(".");
    setupMenuBar();
    setupStatusBar();
    setupMainLayout();
    setWindowTitle(tr("3D Complete Quality Control System"));
    resize(1024,700);
}

Ui::~Ui()
{
    delete viewer;
}

Pcqc* Ui::getMotor()
{
    return motor;
}

pcl::visualization::PCLVisualizer* Ui::getDialogViewer()
{
    return dialogViewer;
}

QDialog* Ui::getComponentDialog()
{
    return addComponentDialog;
}

// SLOT FUNCTIONS
void Ui::about()
{
    QMessageBox::about(this, tr("About pcl-exam-project"), tr("The <b>PCQC</b> is super awesome") );
}

void Ui::aboutPCL()
{
    QMessageBox::about(this, tr("About PCL"), tr("The Point Cloud Library (or PCL) is a large scale,"
                                                 "open project for 3D point cloud processing.") );
}

void Ui::browseLoadTarget()
{
    QString fileName = QFileDialog::getOpenFileName(this, tr("Load Target Point Cloud"), "/home", tr("Point Clouds *.pcd (*.pcd);;All Files (*.*)"));
    pathTField->setText(fileName);
    if(motor->loadTargetCloud(pathTField->displayText()))
    {
        statusBar()->showMessage(pathTField->displayText()+QString(" successfully loaded!"));
        motor->removeAllComponents();
        componentsList->clear();
        targetComponentsList->clear();
        sourceComponentsList->clear();
        checksList->clear();
        showTarget();
    }
    else statusBar()->showMessage(QString("couldn't load the target point cloud, maybe the path or the filename are not correct."));

}

void Ui::browseLoadSource()
{
    if(motor->getTargetCloud()->empty())
    {
        statusBar()->showMessage(QString("Load a reference cloud before starting."));
        return;
    }

    QString fileName = QFileDialog::getOpenFileName(this, tr("Load Source Point Cloud"), "/home", tr("Point Clouds *.pcd (*.pcd);;All Files (*.*)"));
    pathSField->setText(fileName);
    if(motor->loadSourceCloud(pathSField->displayText()))
    {
        statusBar()->showMessage(pathSField->displayText()+QString(" successfully loaded!"));
        sourceComponentsList->clear();
        showRegistered();
    }
    else statusBar()->showMessage(QString("couldn't load the source point cloud, maybe the path or the filename are not correct."));

}

void Ui::clearAll()
{
    viewer->removeAllPointClouds();
    showTarget();
    showRegistered();
}

void Ui::openComponentDialog()
{
    if(motor->getTargetCloud()->empty())
    {
        statusBar()->showMessage(QString("Load a reference cloud before starting."));
        return;
    }

    addComponentDialog = new QDialog(this); // set as child of Ui, to be sure that it will be deleted in the end.
    addComponentDialog->setWindowTitle(QString("Add component..."));

    QTabWidget* componentTabWidget = new QTabWidget();
    QWidget *manualAddComponentTab = new QWidget();
    QWidget *autoAddComponentTab = new QWidget();

    QVBoxLayout *dialogLayout = new QVBoxLayout; // create vertical layout
    QVBoxLayout *manualAddComponentLayout = new QVBoxLayout;
    QVBoxLayout *autoAddComponentLayout = new QVBoxLayout;

    //MANUAL ADD TAB
    dialogVisualizer = new QVTKWidget; // create qvtk widget
    dialogViewer = new pcl::visualization::PCLVisualizer("Dialog Viewer", false);
    dialogVisualizer->SetRenderWindow(dialogViewer->getRenderWindow()); // set as render window the render window of the dialog visualizer
    dialogViewer->setupInteractor(dialogVisualizer->GetInteractor(), dialogVisualizer->GetRenderWindow()); // tells the visualizer what interactor is using now and for what window
    dialogViewer->getInteractorStyle()->setKeyboardModifier(pcl::visualization::INTERACTOR_KB_MOD_SHIFT); // ripristina input system of original visualizer (shift+click for points)
    pcl::PointCloud<pcl::PointXYZRGB>::Ptr temp = motor->getTargetCloud();
    pcl::visualization::PointCloudColorHandlerRGBField<pcl::PointXYZRGB> rgb(temp);
    dialogViewer->addPointCloud<pcl::PointXYZRGB>(temp, rgb, "cloud");
    dialogViewer->setBackgroundColor(0.5, 0.5, 0.5);
    dialogViewer->initCameraParameters();
    dialogViewer->resetCamera();
    componentCallbackConnection = dialogViewer->registerPointPickingCallback(&pointPickCallbackSelectComponent, this);

    QLineEdit *addComponentDialogName  = new QLineEdit("Insert Component Name");
    addComponentDialogName->setObjectName("componentname");

    QHBoxLayout *dialogControlsLayout = new QHBoxLayout;

    QVBoxLayout *buttonsBox = new QVBoxLayout;
    QPushButton *showSegButton = new QPushButton("Segment Component");
    connect(showSegButton, SIGNAL(clicked()), this, SLOT(segmentComponent()));
    QPushButton *resetButton = new QPushButton("Reset Selection");
    connect(resetButton, SIGNAL(clicked()), this, SLOT(resetComponentDialogCallback()));
    buttonsBox->addWidget(showSegButton);
    buttonsBox->addWidget(resetButton);

    QVBoxLayout *numbersBox = new QVBoxLayout;
    QColor *selectedColor = new QColor(0, 0, 0, 255); // initialize color at black
    QPushButton *colorBox = new QPushButton("+-100");
    colorBox->setObjectName("colorbox");
    colorBox->setStyleSheet(colorToStyleSheet(selectedColor));
    colorBox->setMaximumWidth(50);
    QLineEdit *clusterBox = new QLineEdit("1");
    clusterBox->setReadOnly(true);
    clusterBox->setObjectName("clusterbox");
    clusterBox->setMaxLength(5);
    clusterBox->setMaximumWidth(50);
    QLabel *clusterLabel = new QLabel(QString("Clustering threshold"));
    QLabel *colorLabel = new QLabel(QString("Color threshold"));
    numbersBox->addWidget(clusterLabel);
    numbersBox->addWidget(clusterBox);
    numbersBox->addWidget(colorLabel);
    numbersBox->addWidget(colorBox);

    QVBoxLayout *slidersBox = new QVBoxLayout;
    QSlider *setCluThresholdBar = new QSlider(Qt::Horizontal);
    setCluThresholdBar->setRange(0,5000);
    setCluThresholdBar->setValue(1000);
    motor->setClusterSegThreshold(1000);
    setCluThresholdBar->setObjectName("sliderCluster");
    connect(setCluThresholdBar, SIGNAL(sliderReleased()), this, SLOT(setClusterThreshold()));
    QSlider *setColThresholdBar = new QSlider(Qt::Horizontal);
    setColThresholdBar->setRange(0,255);
    setColThresholdBar->setValue(100);
    motor->setColorSegThreshold(100);
    setColThresholdBar->setObjectName("sliderColor");
    connect(setColThresholdBar, SIGNAL(sliderReleased()), this, SLOT(setColorThreshold()));
    slidersBox->addWidget(setCluThresholdBar);
    slidersBox->addWidget(setColThresholdBar);

    dialogControlsLayout->addLayout(buttonsBox);
    dialogControlsLayout->addLayout(numbersBox);
    dialogControlsLayout->addLayout(slidersBox);

    QPushButton *saveComponent = new QPushButton("Save to component list");
    saveComponent->setDefault(true); // default button, pressed if enter is pressed
    connect(saveComponent, SIGNAL(clicked()), this, SLOT(saveComponent()));

    manualAddComponentLayout->addWidget(dialogVisualizer);
    manualAddComponentLayout->addWidget(addComponentDialogName);
    manualAddComponentLayout->addLayout(dialogControlsLayout);
    manualAddComponentLayout->addWidget(saveComponent);
    manualAddComponentTab->setLayout(manualAddComponentLayout);

    // AUTO ADD TAB
    dialogVisualizerAuto = new QVTKWidget;
    dialogViewerAuto = new pcl::visualization::PCLVisualizer("Dialog Viewer Auto", false);
    dialogVisualizerAuto->SetRenderWindow(dialogViewerAuto->getRenderWindow()); // set as render window the render window of the dialog visualizer
    dialogViewerAuto->setupInteractor(dialogVisualizerAuto->GetInteractor(), dialogVisualizerAuto->GetRenderWindow()); // tells the visualizer what interactor is using now and for what window
    pcl::visualization::PointCloudColorHandlerRGBField<pcl::PointXYZRGB> rgbAuto(motor->getTargetCloud());
    dialogViewerAuto->addPointCloud<pcl::PointXYZRGB>(motor->getTargetCloud(), rgbAuto, "cloud");
    dialogViewerAuto->setBackgroundColor(0.5, 0.5, 0.5);
    dialogViewerAuto->initCameraParameters();
    dialogViewerAuto->resetCamera();

    QHBoxLayout *thresholdBoxAuto = new QHBoxLayout;
    QLineEdit *clusterBoxAuto = new QLineEdit("1");
    clusterBoxAuto->setReadOnly(true);
    clusterBoxAuto->setObjectName("clusterboxAuto");
    clusterBoxAuto->setMaxLength(5);
    clusterBoxAuto->setMaximumWidth(50);
    QLabel *clusterLabelAuto = new QLabel(QString("Clustering threshold"));
    QSlider *setCluAutoThresholdBar = new QSlider(Qt::Horizontal);
    setCluAutoThresholdBar->setRange(0,5000);
    setCluAutoThresholdBar->setValue(1000);
    motor->setClusterSegAutoThreshold(1000);
    setCluAutoThresholdBar->setObjectName("sliderClusterAuto");
    connect(setCluAutoThresholdBar, SIGNAL(sliderReleased()), this, SLOT(setClusterAutoThreshold()));
    thresholdBoxAuto->addWidget(clusterLabelAuto);
    thresholdBoxAuto->addWidget(clusterBoxAuto);
    thresholdBoxAuto->addWidget(setCluAutoThresholdBar);

    QHBoxLayout *minPointBoxAuto = new QHBoxLayout;
    QLineEdit *minPointsBox = new QLineEdit("500");
    minPointsBox->setObjectName("minPointsBox");
    motor->setClusterSegMinPoints(500);
    QLabel *minPointsLabel = new QLabel(QString("Minimum number of points in the component"));
    minPointBoxAuto->addWidget(minPointsLabel);
    minPointBoxAuto->addWidget(minPointsBox);

    QHBoxLayout *maxPointBoxAuto = new QHBoxLayout;
    //    int targetCloudSize = motor->getTargetCloud()->size();
    QLineEdit *maxPointsBox = new QLineEdit(QString("%1").arg(motor->getTargetCloud()->size()));
    motor->setClusterSegMaxPoints(motor->getTargetCloud()->size());
    maxPointsBox->setObjectName("maxPointsBox");
    QLabel *maxPointsLabel = new QLabel(QString("Minimum number of points in the component"));
    maxPointBoxAuto->addWidget(maxPointsLabel);
    maxPointBoxAuto->addWidget(maxPointsBox);

    QPushButton *autoFindComponentButton = new QPushButton("Find components");
    connect(autoFindComponentButton, SIGNAL(clicked()), this, SLOT(autoFindComponent()));

    QPushButton *autoAddComponentButton = new QPushButton("Save components found");
    connect(autoAddComponentButton, SIGNAL(clicked()), this, SLOT(autoAddComponent()));

    autoAddComponentLayout->addWidget(dialogVisualizerAuto);
    autoAddComponentLayout->addLayout(thresholdBoxAuto);
    autoAddComponentLayout->addLayout(minPointBoxAuto);
    autoAddComponentLayout->addLayout(maxPointBoxAuto);
    autoAddComponentLayout->addWidget(autoFindComponentButton);
    autoAddComponentLayout->addWidget(autoAddComponentButton);
    autoAddComponentTab->setLayout(autoAddComponentLayout);

    componentTabWidget->addTab(autoAddComponentTab,"Automatic");
    componentTabWidget->addTab(manualAddComponentTab, "Manual");
    dialogLayout->addWidget(componentTabWidget);
    addComponentDialog->setLayout(dialogLayout);

    // DIALOG EXECUTION
    manualAddComponentLayout->deleteLater(); // delete dialog layout when the control returns to the event loop from which deleteLater() was called (after exec i guess)
    addComponentDialog->resize(500,600);
    addComponentDialog->exec();
    componentCallbackConnection.disconnect(); // disconnect the callback function from the viewer
    delete dialogViewer; // finita l'esecuzione, deallocare il viewer (deallocare altra eventuale memoria non indirizzata nel QObject tree).
    delete dialogViewerAuto;
}

void Ui::resetComponentDialogCallback()
{
    dialogViewer->registerPointPickingCallback(&pointPickCallback, this);
    dialogViewer->updatePointCloud(motor->getTargetCloud(),"cloud");
    dialogVisualizer->update();
}

void Ui::setClusterThreshold()
{
    QSlider *slider = addComponentDialog->findChild<QSlider *>("sliderCluster");
    motor->setClusterSegThreshold(slider->value());
    QLineEdit *clusterbox = addComponentDialog->findChild<QLineEdit *>("clusterbox");
    clusterbox->setText(QString("%1").arg((float)slider->value() / 1000));
}

void Ui::setColorThreshold()
{
    QSlider *slider = addComponentDialog->findChild<QSlider *>("sliderColor");
    motor->setColorSegThreshold(slider->value());
    QPushButton *colorbox = addComponentDialog->findChild<QPushButton *>("colorbox");
    colorbox->setText(QString("+-%1").arg(slider->value()));
}

void Ui::setClusterAutoThreshold()
{
    QSlider *slider = addComponentDialog->findChild<QSlider *>("sliderClusterAuto");
    motor->setClusterSegAutoThreshold(slider->value());
    QLineEdit *clusterbox = addComponentDialog->findChild<QLineEdit *>("clusterboxAuto");
    clusterbox->setText(QString("%1").arg((float)slider->value() / 1000));
}

void Ui::setScoreDistanceThreshold()
{
    QSlider *slider= checkCommandBox->findChild<QSlider *>("scoreDistanceSlider");
    motor->setScoreDistanceThreshold(slider->value()/100.0f*6.0f,slider->value()/100.0f*8.0f);
}

void Ui::segmentComponent()
{
    if(motor->componentSegmentation())
        statusBar()->showMessage("Segmented new component.");
    else statusBar()->showMessage("Couldn't segment this selection.");
    dialogViewer->updatePointCloud(motor->getNewComponentCloud(),"cloud");
    dialogVisualizer->update();
}

void Ui::saveComponent()
{
    QLineEdit *componentname = addComponentDialog->findChild<QLineEdit *>("componentname");
    if( motor->componentSave(componentname->text()) )
    {
        componentsList->addItem(componentname->text());
        targetComponentsList->addItem(componentname->text());
        statusBar()->showMessage("Component successfully saved!");
    }
    else statusBar()->showMessage("Couldn't save this component: check component name.");
}

void Ui::deleteComponent()
{
    if(componentsList->selectedItems().isEmpty())
        statusBar()->showMessage("Can't delete component: no components selected.");
    else
    {
        if( motor->componentDelete(componentsList->selectedItems().first()->text()) )
        {
            viewer->removePointCloud(componentsList->selectedItems().first()->text().toStdString() + "trg",v1);
            viewer->removePointCloud(componentsList->selectedItems().first()->text().toStdString() + "src",v2);
            qvtkVisualizer->update();
            targetComponentsList->removeItem(targetComponentsList->findText(componentsList->selectedItems().first()->text())); // delete entry from target component list (combo box)
            sourceComponentsList->removeItem(sourceComponentsList->findText(componentsList->selectedItems().first()->text())); // delete entry from source component list (combo box)
            QList<QListWidgetItem *> checksToDelete = checksList->findItems(componentsList->selectedItems().first()->text() + "-", Qt::MatchStartsWith);
            while(!checksToDelete.isEmpty())
            {
                motor->deleteCheck(checksToDelete.front()->text());
                checksToDelete.pop_front();
            }
            qDeleteAll(checksList->findItems(componentsList->selectedItems().first()->text() + "-", Qt::MatchStartsWith));
            qDeleteAll(componentsList->selectedItems()); // delete entry from components list
            statusBar()->showMessage("Components deleted.");
        }
        else statusBar()->showMessage("Can't delete component: no matching name found in cloud handler.");

    }
}

void Ui::autoFindComponent()
{
    QLineEdit *minPointsValue = addComponentDialog->findChild<QLineEdit *>("minPointsBox");
    QLineEdit *maxPointsValue = addComponentDialog->findChild<QLineEdit *>("maxPointsBox");
    motor->setClusterSegMinPoints(minPointsValue->text().toInt());
    motor->setClusterSegMaxPoints(maxPointsValue->text().toInt());
    componentsFound = motor->findTargetComponents();
    dialogViewerAuto->removeAllPointClouds();
    pcl::visualization::PointCloudColorHandlerRGBField<pcl::PointXYZRGB> rgbAuto(motor->getTargetCloud());
    dialogViewerAuto->addPointCloud<pcl::PointXYZRGB>(motor->getTargetCloud(), rgbAuto, "cloud");
    dialogViewerAuto->resetCamera();
    statusBar()->showMessage(QString("Found %1 components in the reference cloud.").arg(componentsFound));
    QMapIterator<QString, Component> iterator(*(motor->getCurrentTargetComponentsList()));
    while(iterator.hasNext())
    {
        QString currentComponentName = iterator.peekNext().key();
        Component currentComponent = iterator.next().value();
        pcl::PointCloud<pcl::PointXYZRGB>::Ptr currentClusterToShow = currentComponent.getComponentCloud();
        pcl::visualization::PointCloudColorHandlerRandom<pcl::PointXYZRGB> randomColor (currentClusterToShow);
        dialogViewerAuto->addPointCloud<pcl::PointXYZRGB>(currentClusterToShow, randomColor, currentComponentName.toStdString());
    }
    dialogVisualizerAuto->update();
}

void Ui::autoAddComponent()
{
    statusBar()->showMessage(QString("Automatically added %1 components.").arg(componentsFound));
    motor->updateTargetComponentList();
    QMapIterator<QString, Component> iter(*(motor->getTargetComponentsList()));
    while(iter.hasNext())
    {
        QString currentComponentName = iter.next().key();
        if( componentsList->findItems(currentComponentName, Qt::MatchExactly).isEmpty() )
        {
            componentsList->addItem(currentComponentName);
            targetComponentsList->addItem(currentComponentName);
        }
    }
}

void Ui::openCheckDialog()
{
    addCheckDialog = new QDialog(this); // set as child of Ui, to be sure that it will be deleted in the end.
    addCheckDialog->setWindowTitle(QString("Checks definition"));
    QVBoxLayout *dialogLayout = new QVBoxLayout;
    QTabWidget *tabWidget = new QTabWidget();
    tabWidget->setObjectName(QString("tabwidget"));

    // PRESENCE
    QWidget *presenceTab = new QWidget();
    QVBoxLayout *presenceTabLayout = new QVBoxLayout();
    QLabel *presenceCheckNameLabel = new QLabel(QString("Check ID:"));
    QLabel *presenceComponentName = new QLabel();
    presenceComponentName->setObjectName("componentname"); // set object name to be easily found with findChild function
    QLabel *presenceCheckType = new QLabel("-presence");
    presenceCheckType->setObjectName("checktype"); // set object name to be easily found with findChild function
    QGridLayout *presenceFullNameLayout = new QGridLayout(); // use this grid layot to compone and display the check's full name (ID) that will be saved in the checks' list
    presenceFullNameLayout->setHorizontalSpacing(0);
    presenceFullNameLayout->setColumnStretch(0,0);
    presenceFullNameLayout->setColumnStretch(1,5);
    presenceFullNameLayout->addWidget(presenceComponentName, 0, 0);
    presenceFullNameLayout->addWidget(presenceCheckType, 0, 1);
    QLabel *presenceComponentLabel = new QLabel(QString("Component analyzed:"));
    QComboBox *presenceComponentBox = new QComboBox();
    presenceComponentBox->setObjectName("combobox");
    setupChecksComboBox(presenceComponentBox); // fill the combo box with the names of the components in the components' list
    presenceComponentName->setText(presenceComponentBox->currentText()); // set the component name of the check with the selected component in the combo box...
    connect( presenceComponentBox, SIGNAL(currentIndexChanged(QString)), presenceComponentName, SLOT(setText(QString)) ); // ...and do it automatically
    QLabel *presenceThresholdLabel = new QLabel(QString("Minimum % of points to be found:"));
    QLabel *presenceThresholdNumber = new QLabel();
    QSlider *presenceThresholdSlider = new QSlider(Qt::Horizontal);
    connect(presenceThresholdSlider, SIGNAL(valueChanged(int)), presenceThresholdNumber, SLOT(setNum(int)));
    presenceThresholdSlider->setRange(0,100);
    presenceThresholdSlider->setValue(80);
    QPushButton *presenceAdd = new QPushButton(QString("Add Check"));
    connect(presenceAdd, SIGNAL(clicked()), this, SLOT(saveCheck()));
    presenceTabLayout->addWidget(presenceCheckNameLabel);
    presenceTabLayout->addLayout(presenceFullNameLayout);
    presenceTabLayout->addWidget(presenceComponentLabel);
    presenceTabLayout->addWidget(presenceComponentBox);
    presenceTabLayout->addWidget(presenceThresholdLabel);
    presenceTabLayout->addWidget(presenceThresholdNumber);
    presenceTabLayout->addWidget(presenceThresholdSlider);
    presenceTabLayout->addWidget(presenceAdd);
    presenceTab->setLayout(presenceTabLayout);

    // POSITION
    QWidget *positionTab = new QWidget();
    QVBoxLayout *positionTabLayout = new QVBoxLayout();
    QLabel *positionCheckNameLabel = new QLabel(QString("Check ID:"));
    QLabel *positionComponentName = new QLabel();
    positionComponentName->setObjectName("componentname"); // set object name to be easily found with findChild function
    QLabel *positionCheckType = new QLabel("-position");
    positionCheckType->setObjectName("checktype"); // set object name to be easily found with findChild function
    QGridLayout *positionFullNameLayout = new QGridLayout(); // use this grid layot to compone and display the check's full name (ID) that will be saved in the checks' list
    positionFullNameLayout->setHorizontalSpacing(0);
    positionFullNameLayout->setColumnStretch(0,0);
    positionFullNameLayout->setColumnStretch(1,5);
    positionFullNameLayout->addWidget(positionComponentName, 0, 0);
    positionFullNameLayout->addWidget(positionCheckType, 0, 1);
    QLabel *positionComponentLabel = new QLabel(QString("Component analyzed:"));
    QComboBox *positionComponentBox = new QComboBox();
    positionComponentBox->setObjectName("combobox");
    setupChecksComboBox(positionComponentBox); // fill the combo box with the names of the components in the components' list
    positionComponentName->setText(positionComponentBox->currentText()); // set the component name of the check with the selected component in the combo box...
    connect( positionComponentBox, SIGNAL(currentIndexChanged(QString)), positionComponentName, SLOT(setText(QString)) ); // ...and do it automatically
    QLabel *positionThresholdLabel = new QLabel(QString("Maximum distance (10 = 1 mm):"));
    QLabel *positionThresholdNumber = new QLabel();
    QSlider *positionThresholdSlider = new QSlider(Qt::Horizontal);
    connect(positionThresholdSlider, SIGNAL(valueChanged(int)), positionThresholdNumber, SLOT(setNum(int)));
    positionThresholdSlider->setRange(0,100);
    positionThresholdSlider->setValue(30);
    QPushButton *positionAdd = new QPushButton(QString("Add Check"));
    connect(positionAdd, SIGNAL(clicked()), this, SLOT(saveCheck()));
    positionTabLayout->addWidget(positionCheckNameLabel);
    positionTabLayout->addLayout(positionFullNameLayout);
    positionTabLayout->addWidget(positionComponentLabel);
    positionTabLayout->addWidget(positionComponentBox);
    positionTabLayout->addWidget(positionThresholdLabel);
    positionTabLayout->addWidget(positionThresholdNumber);
    positionTabLayout->addWidget(positionThresholdSlider);
    positionTabLayout->addWidget(positionAdd);
    positionTab->setLayout(positionTabLayout);

    // INCLINATION
    QWidget *inclinationTab = new QWidget();
    QVBoxLayout *inclinationTabLayout = new QVBoxLayout();
    QLabel *inclinationCheckNameLabel = new QLabel(QString("Check ID:"));
    QLabel *inclinationComponentName = new QLabel();
    inclinationComponentName->setObjectName("componentname");
    QLabel *inclinationCheckType = new QLabel("-inclination");
    inclinationCheckType->setObjectName("checktype");
    QGridLayout *inclinationFullNameLayout = new QGridLayout();
    inclinationFullNameLayout->setHorizontalSpacing(0);
    inclinationFullNameLayout->setColumnStretch(0,0);
    inclinationFullNameLayout->setColumnStretch(1,5);
    inclinationFullNameLayout->addWidget(inclinationComponentName, 0, 0);
    inclinationFullNameLayout->addWidget(inclinationCheckType, 0, 1);
    QLabel *inclinationComponentLabel = new QLabel(QString("Component analyzed:"));
    QComboBox *inclinationComponentBox = new QComboBox();
    inclinationComponentBox->setObjectName("combobox");
    setupChecksComboBox(inclinationComponentBox);
    inclinationComponentName->setText(inclinationComponentBox->currentText());
    connect( inclinationComponentBox, SIGNAL(currentIndexChanged(QString)), inclinationComponentName, SLOT(setText(QString)) );
    QLabel *inclinationThresholdLabel = new QLabel(QString("Angular difference in decimal degrees (10 = 1 degree):"));
    QLabel *inclinationThresholdNumber = new QLabel();
    QSlider *inclinationThresholdSlider = new QSlider(Qt::Horizontal);
    connect(inclinationThresholdSlider, SIGNAL(valueChanged(int)), inclinationThresholdNumber, SLOT(setNum(int)));
    inclinationThresholdSlider->setRange(0,100);
    inclinationThresholdSlider->setValue(30);
    QPushButton *inclinationAdd = new QPushButton(QString("Add Check"));
    connect(inclinationAdd, SIGNAL(clicked()), this, SLOT(saveCheck()));
    inclinationTabLayout->addWidget(inclinationCheckNameLabel);
    inclinationTabLayout->addLayout(inclinationFullNameLayout);
    inclinationTabLayout->addWidget(inclinationComponentLabel);
    inclinationTabLayout->addWidget(inclinationComponentBox);
    inclinationTabLayout->addWidget(inclinationThresholdLabel);
    inclinationTabLayout->addWidget(inclinationThresholdNumber);
    inclinationTabLayout->addWidget(inclinationThresholdSlider);
    inclinationTabLayout->addWidget(inclinationAdd);
    inclinationTab->setLayout(inclinationTabLayout);

    // ORIENTATION
    QWidget *orientationTab = new QWidget();
    QVBoxLayout *orientationTabLayout = new QVBoxLayout();
    QLabel *orientationCheckNameLabel = new QLabel(QString("Check ID:"));
    QLabel *orientationComponentName = new QLabel();
    orientationComponentName->setObjectName("componentname");
    QLabel *orientationCheckType = new QLabel("-orientation");
    orientationCheckType->setObjectName("checktype");
    QGridLayout *orientationFullNameLayout = new QGridLayout();
    orientationFullNameLayout->setHorizontalSpacing(0);
    orientationFullNameLayout->setColumnStretch(0,0);
    orientationFullNameLayout->setColumnStretch(1,5);
    orientationFullNameLayout->addWidget(orientationComponentName, 0, 0);
    orientationFullNameLayout->addWidget(orientationCheckType, 0, 1);
    QLabel *orientationComponentLabel = new QLabel(QString("Component analyzed:"));
    QComboBox *orientationComponentBox = new QComboBox();
    orientationComponentBox->setObjectName("combobox");
    setupChecksComboBox(orientationComponentBox);
    orientationComponentName->setText(orientationComponentBox->currentText());
    connect( orientationComponentBox, SIGNAL(currentIndexChanged(QString)), orientationComponentName, SLOT(setText(QString)) );
    QLabel *orientationThresholdLabel = new QLabel(QString("Angular difference in decimal degrees (10 = 1 degree):"));
    QLabel *orientationThresholdNumber = new QLabel();
    QSlider *orientationThresholdSlider = new QSlider(Qt::Horizontal);
    connect(orientationThresholdSlider, SIGNAL(valueChanged(int)), orientationThresholdNumber, SLOT(setNum(int)));
    orientationThresholdSlider->setRange(0,100);
    orientationThresholdSlider->setValue(50);
    QPushButton *orientationAdd = new QPushButton(QString("Add Check"));
    connect(orientationAdd, SIGNAL(clicked()), this, SLOT(saveCheck()));
    orientationTabLayout->addWidget(orientationCheckNameLabel);
    orientationTabLayout->addLayout(orientationFullNameLayout);
    orientationTabLayout->addWidget(orientationComponentLabel);
    orientationTabLayout->addWidget(orientationComponentBox);
    orientationTabLayout->addWidget(orientationThresholdLabel);
    orientationTabLayout->addWidget(orientationThresholdNumber);
    orientationTabLayout->addWidget(orientationThresholdSlider);
    orientationTabLayout->addWidget(orientationAdd);
    orientationTab->setLayout(orientationTabLayout);

    tabWidget->addTab(presenceTab, QString("Presence"));
    tabWidget->addTab(positionTab, QString("Position"));
    tabWidget->addTab(inclinationTab, QString("Inclination"));
    tabWidget->addTab(orientationTab, QString("Orientation"));

    dialogLayout->addWidget(tabWidget);
    addCheckDialog->setLayout(dialogLayout);
    addCheckDialog->deleteLater(); // delete dialog when the control returns to the event loop from which deleteLater() was called (after exec i guess)
    dialogLayout->deleteLater(); // delete dialog layout when the control returns to the event loop from which deleteLater() was called (after exec i guess)
    addCheckDialog->resize(640, 240);
    addCheckDialog->exec();
}

void Ui::saveCheck()
{
    QTabWidget *tabWidget = addCheckDialog->findChild<QTabWidget *>("tabwidget");
    QWidget *currentWidget = tabWidget->currentWidget();
    QLabel *checkname = currentWidget->findChild<QLabel *>("componentname");
    QLabel *checkType = currentWidget->findChild<QLabel *>("checktype");
    QString fullname = checkname->text() + checkType->text();
    QComboBox *comboBox = currentWidget->findChild<QComboBox *>("combobox");
    QSlider *slider = currentWidget->findChild<QSlider *>();
    CheckType type;
    float threshold=0;
    switch (tabWidget->currentIndex())
    {
    case 0:
        threshold = slider->value();
        type = PRESENCE;
        break;
    case 1:
        threshold = slider->value()/10.0f;
        type = POSITION;
        break;
    case 2:
        threshold = slider->value()/10.0f;
        type = INCLINATION;
        break;
    case 3:
        threshold = slider->value()/10.0f;
        type = ORIENTATION;
        break;
    }

    if( motor->addCheck( fullname, comboBox->currentText(), type, threshold ))
    {
        statusBar()->showMessage( QString("%1 check added to checks list.").arg(fullname) );
        checksList->addItem(fullname);
    }
    else statusBar()->showMessage( QString("Couldn't save this check: check check's name.") );
}

void Ui::deleteCheck()
{
    if(checksList->selectedItems().isEmpty())
        statusBar()->showMessage("Can't delete check: no check selected.");
    else
    {
        if( motor->deleteCheck(checksList->selectedItems().first()->text()))
        {
            qDeleteAll(checksList->selectedItems()); // delete entry from components list
            statusBar()->showMessage("Check deleted.");
        }
        else statusBar()->showMessage("Can't delete check: no matching name found in checks' handler.");
    }
}

void Ui::check()
{
    // INITIAL CHECKS
    if(motor->getTargetCloud()->empty())
    {
        statusBar()->showMessage(QString("Load a reference cloud before starting."));
        return;
    }
    if(motor->getSourceCloud()->empty())
    {
        statusBar()->showMessage(QString("Load an sample cloud before starting."));
        return;
    }

    //    resultsList->clear();
    QApplication::setOverrideCursor(QCursor(Qt::WaitCursor));
    resultsList->append(QString("================= Analysis START =================\n"));

    // REGISTRATION
    if(!motor->isRegistrationAlreadyPerformed())
    {
        statusBar()->showMessage("Registration...");
        motor->registration();
        showRegistered();
        statusBar()->showMessage("Registration...OK");
    }

    time_t start,end;
    time (&start);

    if(componentsList->count() != 0)
    {
        // COMPONENT MATCHING
        statusBar()->showMessage("Components matching...");
        resultsList->append(QString("Components matching..."));
        sourceComponentsList->clear();
        motor->findSourceComponents();
        setupSourceComboBox(); // fill the source components combo box with the names of the items discovered
        resultsList->append(QString("%1 of %2 components matched.").arg(sourceComponentsList->count()).arg(targetComponentsList->count()));
        statusBar()->showMessage("Components matching...OK");

        // VERIFY SOURCE COMPONENTS PROPERTIES
        if (checksList->count() != 0)
        {
            statusBar()->showMessage("Components check...");
            resultsList->append(QString("Components check..."));
        }
        QMap<QString, bool> results = motor->performChecks();
        QMapIterator<QString, bool> iter(results);
        while (iter.hasNext())
        {
            if(iter.next().value() == true)
                resultsList->append( QString("Check %1 : CORRECT").arg(iter.key()));
            else resultsList->append( QString("Check %1 : ERROR").arg(iter.key()));
        }
        statusBar()->showMessage("Components check...OK");
        time (&end);
        double dif = difftime (end,start);
        cout << "------------------------------------->  All checks performed in " << dif << " seconds"<< endl;
    }
    else
    {
        statusBar()->showMessage("No components selected, performing difference analysis...");
        resultsList->append(QString("No components selected, performing difference analysis..."));
        int numberOfErrors = motor->segmentDifferences();
        resultsList->append( QString("Number of wrong components: %1").arg(numberOfErrors) );
        statusBar()->showMessage("No components selected, performing difference analysis... OK");

        viewer->removePointCloud("difference");
        pcl::visualization::PointCloudColorHandlerCustom<pcl::PointXYZRGB> red(motor->getDifferenceCloud(), 255, 0, 0); // color the difference cloud in red
        viewer->addPointCloud<pcl::PointXYZRGB>(motor->getDifferenceCloud(), red, "difference", v1);
        statusBar()->showMessage(QString("Difference point cloud added to the visualizer."));
        qvtkVisualizer->update();
    }
    resultsList->append(QString("\n================== Analysis END ==================\n"));
    QApplication::restoreOverrideCursor();
}

void Ui::showTarget()
{
    viewer->removeAllPointClouds(v1);
    pcl::visualization::PointCloudColorHandlerRGBField<pcl::PointXYZRGB> rgb(motor->getTargetCloud());
    viewer->addPointCloud<pcl::PointXYZRGB>(motor->getTargetCloud(), rgb, "target", v1);
    viewer->resetCamera();
    qvtkVisualizer->update();
}

void Ui::showRegistered()
{
    viewer->removeAllPointClouds(v2);
    pcl::visualization::PointCloudColorHandlerRGBField<pcl::PointXYZRGB> rgb(motor->getRegisteredCloud());
    viewer->addPointCloud<pcl::PointXYZRGB>(motor->getRegisteredCloud(), rgb, "registered", v2);
    viewer->resetCamera();
    qvtkVisualizer->update();
}

void Ui::showDifference()
{
    if(!viewer->removePointCloud("difference"))
    {
        pcl::visualization::PointCloudColorHandlerCustom<pcl::PointXYZRGB> red(motor->getDifferenceCloud(), 255, 0, 0); // color the difference cloud in red
        viewer->addPointCloud<pcl::PointXYZRGB>(motor->getDifferenceCloud(), red, "difference", v1);
        statusBar()->showMessage(QString("Difference point cloud added to the visualizer."));
    }
    else statusBar()->showMessage(QString("Difference point cloud removed from the visualizer."));
    qvtkVisualizer->update();
}

void Ui::showArdoranRegistered()
{
    viewerArdoran->removeAllPointClouds();
    viewerArdoran->removeAllShapes();
    pcl::visualization::PointCloudColorHandlerRGBField<pcl::PointXYZRGB> rgb(motor->getArdoranRegisteredCloud());
    viewerArdoran->addPointCloud<pcl::PointXYZRGB>(motor->getArdoranRegisteredCloud(), rgb, "sample");
    viewerArdoran->addCube(22.0f, 30.0f, 120.0f, 140.0f, 407.0f, 415.0f, 255, 0, 0, "basecube");
    viewerArdoran->addCube(-33.0f, -28.0f, 130.0f, 143.0f, 397.0f, 403.0f, 0, 255, 0,"sidecube");
    viewerArdoran->resetCamera();
    qvtkVisualizerArdoran->update();
}

void Ui::showTargetComponent()
{
    if(targetComponentsList->currentText() == "")
        return;
    if(  !viewer->removePointCloud( targetComponentsList->currentText().toStdString()+"trg" )  )
    {
        pcl::visualization::PointCloudColorHandlerCustom<pcl::PointXYZRGB> green( motor->getTargetComponentCloud(targetComponentsList->currentText()), 0, 255, 0 );
        viewer->addPointCloud<pcl::PointXYZRGB>( motor->getTargetComponentCloud(targetComponentsList->currentText()), green, targetComponentsList->currentText().toStdString()+"trg", v1);
        statusBar()->showMessage(QString("%1 point cloud added from the visualizer.").arg(targetComponentsList->currentText()));
    }
    else statusBar()->showMessage(QString("%1 point cloud removed to the visualizer.").arg(targetComponentsList->currentText()));
    qvtkVisualizer->update();
}

void Ui::showSourceComponent()
{
    if(sourceComponentsList->currentText() == "")
        return;
    if( !viewer->removePointCloud( sourceComponentsList->currentText().toStdString()+"src" ) )
    {
        pcl::visualization::PointCloudColorHandlerCustom<pcl::PointXYZRGB> blue( motor->getSourceComponentCloud(targetComponentsList->currentText()), 0, 0, 255);
        viewer->addPointCloud<pcl::PointXYZRGB>( motor->getSourceComponentCloud(sourceComponentsList->currentText()), blue, sourceComponentsList->currentText().toStdString()+"src", v2 );
        statusBar()->showMessage(QString("%1 point cloud added from the visualizer.").arg(sourceComponentsList->currentText()));
    }
    else statusBar()->showMessage(QString("%1 point cloud removed to the visualizer.").arg(sourceComponentsList->currentText()));
    qvtkVisualizer->update();
}

void Ui::showComponent()
{
    if(targetComponentsList->currentText() == "")
        return;
    if(  !viewer->removePointCloud( targetComponentsList->currentText().toStdString()+"trg" )  )
    {
        double r,g,b;
        pcl::visualization::getRandomColors(r, g, b);
        int r_ = static_cast<int> (pcl_lrint (r * 255.0)),
                g_ = static_cast<int> (pcl_lrint (g * 255.0)),
                b_ = static_cast<int> (pcl_lrint (b * 255.0));
        pcl::visualization::PointCloudColorHandlerCustom<pcl::PointXYZRGB> targetComponentRandomColor( motor->getTargetComponentCloud(targetComponentsList->currentText()), r_, g_, b_);
        pcl::visualization::PointCloudColorHandlerCustom<pcl::PointXYZRGB> sourceComponentRandomColor( motor->getSourceComponentCloud(targetComponentsList->currentText()), r_, g_, b_);
        viewer->addPointCloud<pcl::PointXYZRGB>( motor->getTargetComponentCloud(targetComponentsList->currentText()), targetComponentRandomColor, targetComponentsList->currentText().toStdString()+"trg", v1);
        viewer->addPointCloud<pcl::PointXYZRGB>( motor->getSourceComponentCloud(targetComponentsList->currentText()), sourceComponentRandomColor, targetComponentsList->currentText().toStdString()+"src", v2 );
        statusBar()->showMessage(QString("%1 point cloud added from the visualizer.").arg(targetComponentsList->currentText()));
    }
    else
    {
        viewer->removePointCloud( targetComponentsList->currentText().toStdString()+"src" );
        statusBar()->showMessage(QString("%1 point cloud removed to the visualizer.").arg(targetComponentsList->currentText()));
    }
    qvtkVisualizer->update();
}

// UI FUNCTIONS

void Ui::setupMenuBar()
{
    QAction* quitAct = new QAction(tr("&Quit"), this);
    quitAct->setShortcuts(QKeySequence::Quit);
    quitAct->setStatusTip(tr("Quit the application"));
    connect(quitAct, SIGNAL(triggered()), this, SLOT(close()));
    QAction* aboutAct = new QAction(tr("&About"), this);
    aboutAct->setStatusTip(tr("Show the application's About box"));
    connect(aboutAct, SIGNAL(triggered()), this, SLOT(about()));
    QAction* aboutQtAct = new QAction(tr("About &Qt"), this);
    aboutQtAct->setStatusTip(tr("Show the Qt library's About box"));
    connect(aboutQtAct, SIGNAL(triggered()), qApp, SLOT(aboutQt()));
    QAction* aboutPCLAct = new QAction(tr("About &PCL"), this);
    aboutPCLAct->setStatusTip(tr("Show the PCL library's About box"));
    connect(aboutPCLAct, SIGNAL(triggered()), this, SLOT(aboutPCL()));
    QMenu* fileMenu = menuBar()->addMenu(tr("&File"));
    fileMenu->addAction(quitAct);
    QMenu* helpMenu = menuBar()->addMenu(tr("&Help"));
    helpMenu->addAction(aboutAct);
    helpMenu->addAction(aboutQtAct);
    helpMenu->addAction(aboutPCLAct);
}

void Ui::setupStatusBar()
{
    statusBar()->showMessage(tr("Ready"));
}

void Ui::setupLoadTBox()
{
    loadTBox = new QGroupBox(QString("Load Reference Cloud"));
    QPushButton* browseTButton = new QPushButton(QString("Browse..."));
    connect(browseTButton, SIGNAL(clicked()), this, SLOT(browseLoadTarget()));
    pathTField = new QLineEdit();
    if (launchDirectory.exists("reference.pcd"))
        pathTField->setText(launchDirectory.absoluteFilePath("reference.pcd"));
    QHBoxLayout* loadTargetLayout = new QHBoxLayout;
    loadTargetLayout->addWidget(browseTButton);
    loadTargetLayout->addWidget(pathTField);
    loadTBox->setLayout(loadTargetLayout);
}

void Ui::setupComponentsBox()
{
    componentsBox = new QGroupBox(QString("Components Definition"));
    QVBoxLayout* componentButtonsLayout = new QVBoxLayout;
    QPushButton* addComponentButton = new QPushButton(QString("Add..."));
    connect(addComponentButton, SIGNAL(clicked()), this, SLOT(openComponentDialog()));
    QPushButton* delComponentButton = new QPushButton(QString("Delete"));
    connect(delComponentButton, SIGNAL(clicked()), this, SLOT(deleteComponent()));
    componentButtonsLayout->addWidget(addComponentButton);
    componentButtonsLayout->addWidget(delComponentButton);
    QHBoxLayout* componentsLayout = new QHBoxLayout;
    componentsList = new QListWidget;
    componentsList->setSelectionMode(QAbstractItemView::SingleSelection);
    //    connect(componentsList, SIGNAL(itemClicked(QListWidgetItem*)), componentsList, SLOT(s))
    componentsLayout->addLayout(componentButtonsLayout);
    componentsLayout->addWidget(componentsList);
    componentsBox->setLayout(componentsLayout);
}

void Ui::setupChecksBox()
{
    checksBox = new QGroupBox(QString("Checks Definition"));
    QVBoxLayout* checkButtonsLayout = new QVBoxLayout;
    QPushButton* addCheckButton = new QPushButton(QString("Add..."));
    connect(addCheckButton, SIGNAL(clicked()), this, SLOT(openCheckDialog()));
    QPushButton* delCheckButton = new QPushButton(QString("Delete"));
    connect(delCheckButton, SIGNAL(clicked()), this, SLOT(deleteCheck()));
    checkButtonsLayout->addWidget(addCheckButton);
    checkButtonsLayout->addWidget(delCheckButton);
    QHBoxLayout* checksLayout = new QHBoxLayout;
    checksList = new QListWidget;
    checksLayout->addLayout(checkButtonsLayout);
    checksLayout->addWidget(checksList);
    checksBox->setLayout(checksLayout);
}

void Ui::setupLoadSBox()
{
    loadSBox = new QGroupBox(QString("Load Sample Cloud"));
    QPushButton* browseSButton = new QPushButton(QString("Browse..."));
    connect(browseSButton, SIGNAL(clicked()), this, SLOT(browseLoadSource()));
    pathSField = new QLineEdit();
    if (launchDirectory.exists("sample.pcd"))
        pathSField->setText(launchDirectory.absoluteFilePath("sample.pcd"));
    QHBoxLayout* loadSourceLayout = new QHBoxLayout;
    loadSourceLayout->addWidget(browseSButton);
    loadSourceLayout->addWidget(pathSField);
    loadSBox->setLayout(loadSourceLayout);
}

void Ui::setupVisualizer()
{
    qvtkVisualizer = new QVTKWidget();// create qvtk widget
    viewer = new pcl::visualization::PCLVisualizer("3DViewer", false);// don't display in the vtk visualizer, render it on a qt window
    qvtkVisualizer->SetRenderWindow(viewer->getRenderWindow());// set as render window the render window of the pcl visualizer
    viewer->setupInteractor(qvtkVisualizer->GetInteractor(), qvtkVisualizer->GetRenderWindow());// tells the visualizer what interactor is using now and for what window
    viewer->getInteractorStyle()->setKeyboardModifier(pcl::visualization::INTERACTOR_KB_MOD_SHIFT);// ripristina input system of original visualizer (shift+click for points)

    viewer->createViewPort(0.0, 0.5, 1.0, 1.0, v1);
    viewer->setBackgroundColor(0.5, 0.5, 0.5, v1);
    viewer->addText("REFERENCE CLOUD", 30, 20,"REFERENCE CLOUD",v1);

    viewer->createViewPort(0.0, 0.0, 1.0, 0.5, v2);
    viewer->setBackgroundColor(0.5, 0.5, 0.5, v2);
    viewer->addText("SAMPLE CLOUD", 30, 20,"SAMPLE CLOUD",v2);

    viewer->initCameraParameters();
    viewer->registerPointPickingCallback(&pointPickCallback, this); // callback function for interaction with the mouse on the visualizer
}

void Ui::setupResultsBox()
{
    resultsBox = new QGroupBox(QString("Results Analysis"));
    resultsList = new QTextEdit;
    resultsList->setReadOnly(true);
    QHBoxLayout* resultsLayout = new QHBoxLayout;
    resultsLayout->addWidget(resultsList);
    resultsBox->setLayout(resultsLayout);
}

void Ui::setuCheckCommandBox()
{
    checkCommandBox = new QGroupBox(QString("Start check"));
    QPushButton* checkButton = new QPushButton(QString("Check"));
    QSlider* scoreDistanceThresholdSetter = new QSlider(Qt::Horizontal);
    QLabel* sliderLabel = new QLabel(QString("Check sensibility:"));
    scoreDistanceThresholdSetter->setRange(0,100);
    scoreDistanceThresholdSetter->setValue(20);
    scoreDistanceThresholdSetter->setObjectName("scoreDistanceSlider");
    connect(scoreDistanceThresholdSetter,SIGNAL(sliderReleased()),this, SLOT(setScoreDistanceThreshold()));
    connect(checkButton, SIGNAL(clicked()), this, SLOT(check()));

    QVBoxLayout* checkSliderLayout = new QVBoxLayout;
    checkSliderLayout->addWidget(checkButton);
    checkSliderLayout->addWidget(sliderLabel);
    checkSliderLayout->addWidget(scoreDistanceThresholdSetter);
    checkCommandBox->setLayout(checkSliderLayout);
}

void Ui::setupVisualizerCommandsBox()
{
    visualizerCommandsBox = new QGroupBox("Visualizer Commands");
    QVBoxLayout* visualizerCommandsLayout = new QVBoxLayout;
    QPushButton* showDButton = new QPushButton(QString("Show/Hide Difference Cloud"));
    connect(showDButton, SIGNAL(clicked()), this, SLOT(showDifference()));
    QPushButton* showComponentButton = new QPushButton(QString("Show/Hide Component"));
    connect(showComponentButton, SIGNAL(clicked()), this, SLOT(showComponent()));
    targetComponentsList = new QComboBox;
    QHBoxLayout* showComponentLayout = new QHBoxLayout;
    showComponentLayout->addWidget(showComponentButton);
    showComponentLayout->addWidget(targetComponentsList,1);
    QPushButton* clearAllButton = new QPushButton(QString("Hide All Components"));
    connect(clearAllButton, SIGNAL(clicked()), this, SLOT(clearAll()));
//    QPushButton* showSComponentButton = new QPushButton(QString("Show/Hide Source Component"));
//    connect(showSComponentButton, SIGNAL(clicked()), this, SLOT(showSourceComponent()));
    sourceComponentsList = new QComboBox;
//    QHBoxLayout* showSourceComponentLayout = new QHBoxLayout;
//    showSourceComponentLayout->addWidget(showSComponentButton);
//    showSourceComponentLayout->addWidget(sourceComponentsList, 1);

    visualizerCommandsLayout->addWidget(showDButton);
    visualizerCommandsLayout->addLayout(showComponentLayout);
//    visualizerCommandsLayout->addLayout(showSourceComponentLayout);
    visualizerCommandsLayout->addWidget(clearAllButton);


    visualizerCommandsBox->setLayout(visualizerCommandsLayout);
}

void Ui::setupMainLayout()
{
    QTabWidget* mainTabWidget = new QTabWidget();

    QWidget* mainWidget = new QWidget;
    QHBoxLayout* mainLayout = new QHBoxLayout;
    QVBoxLayout* leftCommandsLayout = new QVBoxLayout;
    QVBoxLayout* visualizerLayout = new QVBoxLayout;
    QHBoxLayout* rightCommandsLayout = new QHBoxLayout;


    QWidget* ardoranWidget = new QWidget;
    QHBoxLayout* ardoranLayout = new QHBoxLayout;
    QVBoxLayout* commandsArdoranLayout = new QVBoxLayout;

    setupLoadTBox();
    setupComponentsBox();
    setupChecksBox();
    setupLoadSBox();
    setupVisualizer();
    setupResultsBox();
    setuCheckCommandBox();
    setupVisualizerCommandsBox();

    loadTBox->setMaximumWidth(475);
    componentsBox->setMaximumWidth(475);
    checksBox->setMaximumWidth(475);
    loadSBox->setMaximumWidth(475);
    resultsBox->setMaximumWidth(475);
    checkCommandBox->setMaximumWidth(200);
    visualizerCommandsBox->setMinimumWidth(400);
    leftCommandsLayout->addWidget(loadTBox);
    leftCommandsLayout->addWidget(loadSBox);
    leftCommandsLayout->addWidget(componentsBox, 1);
    leftCommandsLayout->addWidget(checksBox, 1);
    leftCommandsLayout->addWidget(resultsBox);
    rightCommandsLayout->addWidget(checkCommandBox , 1);
    rightCommandsLayout->addWidget(visualizerCommandsBox);
    visualizerLayout->addWidget(qvtkVisualizer);
    visualizerLayout->addLayout(rightCommandsLayout);
    mainLayout->addLayout(leftCommandsLayout);
    mainLayout->addLayout(visualizerLayout);
    mainWidget->setLayout(mainLayout);


    //    setupLoadTBoxArdoran();
    setupLoadSBoxArdoran();
    setupMultiLoadSBoxArdoran();
    setupVisualizerArdoran();
    setupResultsBoxArdoran();

    //    commandsArdoranLayout->addWidget(loadTBoxArdoran);
    commandsArdoranLayout->addWidget(loadSBoxArdoran);
    commandsArdoranLayout->addWidget(loadMBoxArdoran);
    commandsArdoranLayout->addWidget(resultsBoxArdoran);
    ardoranLayout->addLayout(commandsArdoranLayout);
    ardoranLayout->addWidget(qvtkVisualizerArdoran);
    ardoranWidget->setLayout(ardoranLayout);

    mainTabWidget->addTab(mainWidget, QString("PCQC"));
    mainTabWidget->addTab(ardoranWidget, QString("Ardoran"));

    setCentralWidget(mainTabWidget);
}

void Ui::pointPickCallback(const pcl::visualization::PointPickingEvent& event, void* cookie)
{
    Ui *ui = (Ui*)cookie;
    float x,y,z;
    if (event.getPointIndex() == -1)
        ui->statusBar()->showMessage(tr("No point was clicked"));
    else
    {
        event.getPoint(x,y,z);
        ui->statusBar()->showMessage(QString("Point Clicked index: %1 x: %2 y: %3 z: %4")
                                     .arg(event.getPointIndex())
                                     .arg(x)
                                     .arg(y)
                                     .arg(z)
                                     );
    }
}

void Ui::pointPickCallbackSelectComponent(const pcl::visualization::PointPickingEvent& event, void* cookie)
{
    Ui *ui = (Ui*)cookie;
    float x,y,z;
    if (event.getPointIndex() == -1)
        ui->statusBar()->showMessage(tr("No point was clicked"));
    else
    {
        event.getPoint(x,y,z);
        ui->statusBar()->showMessage(QString("Point Clicked index: %1 x: %2 y: %3 z: %4")
                                     .arg(event.getPointIndex())
                                     .arg(x)
                                     .arg(y)
                                     .arg(z)
                                     );
        QPushButton *colorbox = ui->getComponentDialog()->findChild<QPushButton *>("colorbox");
        colorbox->setStyleSheet(colorToStyleSheet(ui->getMotor()->getPointColor(event.getPointIndex())));
        ui->getMotor()->componentSelection(event.getPointIndex());
        ui->getDialogViewer()->updatePointCloud(ui->getMotor()->getNewComponentCloud(),"cloud");
    }
}

QString Ui::colorToStyleSheet(QColor *color)
{
    QString styleSheet = QString("* { background-color: rgb(%1,%2,%3) }")
            .arg(color->red())
            .arg(color->green())
            .arg(color->blue());
    return styleSheet;
}

void Ui::setupSourceComboBox()
{
    QMap<QString, Component> *list = motor->getSourceComponentsList();
    QMapIterator<QString, Component> iter(*list);
    while (iter.hasNext())
    {
        iter.next(); // step to the next item
        sourceComponentsList->addItem(iter.key()); //get the key of the item, i.e. the name of the component
    }
}

void Ui::setupChecksComboBox(QComboBox *cb)
{
    QMap<QString, Component> *list = motor->getTargetComponentsList();
    QMapIterator<QString, Component> iter(*list);
    while (iter.hasNext())
    {
        iter.next(); // step to the next item
        cb->addItem(iter.key()); //get the key of the item, i.e. the name of the component
    }
}


//------------------------------------------------------------------------------------------------------------
//-------------------------------------  ARDORAN -------------------------------------------------------------
//------------------------------------------------------------------------------------------------------------

void Ui::setupLoadSBoxArdoran()
{
    loadSBoxArdoran = new QGroupBox(QString("Load Sample Cloud"));
    QPushButton* browseSButton = new QPushButton(QString("Browse..."));
    connect(browseSButton, SIGNAL(clicked()), this, SLOT(browseLoadSourceArdoran()));
    pathSFieldArdoran = new QLineEdit();
    if (launchDirectory.exists("ardoran-sample.pcd"))
        pathSFieldArdoran->setText(launchDirectory.absoluteFilePath("ardoran-sample.pcd"));
    QHBoxLayout* loadSourceLayout = new QHBoxLayout;
    loadSourceLayout->addWidget(browseSButton);
    loadSourceLayout->addWidget(pathSFieldArdoran);
    loadSBoxArdoran->setLayout(loadSourceLayout);
}

void Ui::setupMultiLoadSBoxArdoran()
{
    loadMBoxArdoran = new QGroupBox(QString("Load an entire folder to analyze"));
    QPushButton* browseMButton = new QPushButton(QString("Browse..."));
    connect(browseMButton, SIGNAL(clicked()), this, SLOT(browseLoadMultiSourceArdoran()));
    pathMFieldArdoran = new QLineEdit();
    QHBoxLayout* loadMultiLayout = new QHBoxLayout;
    loadMultiLayout->addWidget(browseMButton);
    loadMultiLayout->addWidget(pathMFieldArdoran);
    loadMBoxArdoran->setLayout(loadMultiLayout);
}

void Ui::setupVisualizerArdoran()
{
    qvtkVisualizerArdoran = new QVTKWidget();// create qvtk widget
    viewerArdoran = new pcl::visualization::PCLVisualizer("3DViewerArdoran", false);// don't display in the vtk visualizer, render it on a qt window
    qvtkVisualizerArdoran->SetRenderWindow(viewerArdoran->getRenderWindow());// set as render window the render window of the pcl visualizer
    viewerArdoran->setupInteractor(qvtkVisualizerArdoran->GetInteractor(), qvtkVisualizerArdoran->GetRenderWindow());// tells the visualizer what interactor is using now and for what window
    viewerArdoran->getInteractorStyle()->setKeyboardModifier(pcl::visualization::INTERACTOR_KB_MOD_SHIFT);// ripristina input system of original visualizer (shift+click for points)
    viewerArdoran->setBackgroundColor(0.5, 0.5, 0.5);
    viewerArdoran->addText("ARDORAN CLOUD", 30, 20,"ARDORAN CLOUD");
    viewerArdoran->initCameraParameters();
    viewerArdoran->registerPointPickingCallback(&pointPickCallback, this); // callback function for interaction with the mouse on the visualizer
}

void Ui::setupResultsBoxArdoran()
{
    resultsBoxArdoran = new QGroupBox(QString("Ribbon cable check"));
    QPushButton* checkButton = new QPushButton(QString("Check"));
    connect(checkButton, SIGNAL(clicked()), this, SLOT(checkArdoran()));
    resultsListArdoran = new QTextEdit;
    resultsListArdoran->setReadOnly(true);
    QHBoxLayout* resultsLayout = new QHBoxLayout;
    resultsLayout->addWidget(checkButton);
    resultsLayout->addWidget(resultsListArdoran);
    resultsBoxArdoran->setLayout(resultsLayout);
}

void Ui::browseLoadTargetArdoran()
{
    QString fileName = QFileDialog::getOpenFileName(this, tr("Load Target Point Cloud"), "/home", tr("Point Clouds *.pcd (*.pcd);;All Files (*.*)"));
    pathTFieldArdoran->setText(fileName);
    if(motor->loadArdoranReferenceCloud(pathTFieldArdoran->displayText()))
    {
        statusBar()->showMessage(pathTFieldArdoran->displayText()+QString(" successfully loaded!"));
    }
    else statusBar()->showMessage(QString("couldn't load the target point cloud, maybe the path or the filename are not correct."));

}

void Ui::browseLoadSourceArdoran()
{
    if(motor->getArdoranReferenceCloud()->empty())
    {
        statusBar()->showMessage(QString("Load a reference cloud before starting."));
        return;
    }

    QString fileName = QFileDialog::getOpenFileName(this, tr("Load Source Point Cloud"), "/home", tr("Point Clouds *.pcd (*.pcd);;All Files (*.*)"));
    pathSFieldArdoran->setText(fileName);
    pathMFieldArdoran->setText("");
    files = new QStringList;
    files->append(pathSFieldArdoran->displayText());
    if(motor->loadArdoranSampleCloud(pathSFieldArdoran->displayText()))
    {
        statusBar()->showMessage(pathSFieldArdoran->displayText()+QString(" successfully loaded!"));
        showArdoranRegistered();

    }
    else statusBar()->showMessage(QString("couldn't load the source point cloud, maybe the path or the filename are not correct."));

}
void Ui::browseLoadMultiSourceArdoran()
{
    if(motor->getArdoranReferenceCloud()->empty())
    {
        statusBar()->showMessage(QString("Reference cloud not found."));
        return;
    }

    QString pathName = QFileDialog::getExistingDirectory(this, tr("Choose a Directory"), "/home", /*QFileDialog::DontUseNativeDialog |*/ QFileDialog::ReadOnly | QFileDialog::ShowDirsOnly);
    pathMFieldArdoran->setText(pathName);
    pathSFieldArdoran->setText("");
    QDir directory = QDir(pathName);
    QStringList *fileNames = new QStringList(directory.entryList(QStringList(QString("*.pcd")), QDir::Files | QDir::NoSymLinks));
    files = new QStringList;
    while (!fileNames->isEmpty())
    {
        files->append(pathMFieldArdoran->text() + "/" + fileNames->first());
        fileNames->pop_front();
    }
    if(!files->isEmpty())
    {
        statusBar()->showMessage(QString("Opened %1: found %2 .pcd files into the directory").arg(pathMFieldArdoran->text()).arg(files->size()));
        if( motor->loadArdoranSampleCloud( files->first() ) )
        {
            //            statusBar()->showMessage( files->first() + QString(" successfully loaded!") );
            showArdoranRegistered();
        }
        else statusBar()->showMessage(QString("Couldn't load the source point cloud, maybe the path or the filename are not correct."));
    }
    else
        statusBar()->showMessage(QString("Couldn't find .pcd file into the directory."));
}

void Ui::checkArdoran()
{
    if(motor->getArdoranSampleCloud()->size() == 0 || motor->getArdoranReferenceCloud()->size() == 0)
        statusBar()->showMessage(QString("Please, load a cloud before executing."));
    else
    {
        QApplication::setOverrideCursor(QCursor(Qt::WaitCursor));
        QStringListIterator sourceIterator(*files);
        while(sourceIterator.hasNext())
        {
            // SOURCE CLOUD LOADER
            motor->loadArdoranSampleCloud(sourceIterator.peekNext());

            if(!motor->isArdoranRegistrationAlreadyPerformed())
            {
                statusBar()->showMessage("Registration...");
                motor->registrationArdoran();
                showArdoranRegistered();
                statusBar()->showMessage("Registration...OK");
            }
            statusBar()->showMessage(QString("Computing..."));
            bool baseIsConnected = motor->checkBaseArdoran();
            bool sideIsConnected = motor->checkSideArdoran();
            statusBar()->showMessage(QString("Done!"));
            resultsListArdoran->append(">> Checking...\n      " + sourceIterator.peekNext());
            if(baseIsConnected)
                resultsListArdoran->append(QString("      Base: CONNECTED"));
            else
                resultsListArdoran->append(QString("      Base: DISCONNECTED"));
            if(sideIsConnected)
                resultsListArdoran->append(QString("      Side: CONNECTED\n"));
            else
                resultsListArdoran->append(QString("      Side: DISCONNECTED\n"));
            sourceIterator.next();
        }
        QApplication::restoreOverrideCursor();
    }

}
